package com.zyx.concurrentdemo.c06cas;

import lombok.extern.slf4j.Slf4j;
import sun.misc.Unsafe;

/**
 * @author Yaxi.Zhang
 * @since 2021/10/18 14:23
 * desc: 使用 Unsafe 类实现自定义的带有cas的Integer
 */
@Slf4j(topic = "c.TestMyAtomicInteger")
public class TestMyAtomicInteger {
    public static void main(String[] args) {
        Account.demo(new MyAtomicInteger(10000));
    }
}

@Slf4j(topic = "c.MyAtomicInteger")
class MyAtomicInteger implements Account {

    private final int value;
    private static final long VALUE_OFFSET;
    private static final Unsafe UNSAFE;

    public MyAtomicInteger(int value) {
        this.value = value;
    }

    static {
        UNSAFE = UnsafeAccessor.getUnsafe();
        try {
            VALUE_OFFSET = UNSAFE.objectFieldOffset(MyAtomicInteger.class.getDeclaredField("value"));
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public void substract(int amount) {
        while (true) {
            int prev = this.value;
            int next = prev - amount;
            // 更新数据
            if (UNSAFE.compareAndSwapInt(this, VALUE_OFFSET, prev, next)) {
                log.debug("remaining:{}", value);
                break;
            }
        }
    }

    @Override
    public Integer getBalance() {
        return this.value;
    }

    @Override
    public void withdraw(Integer amount) {
        substract(amount);
    }
}

